/*
 * hash_link_table.h
 *
 *  Created on: Aug 31, 2012
 *      Author: root
 */

#ifndef HASH_LINK_TABLE_H_
#define HASH_LINK_TABLE_H_

#include "utils.h"
/*
*T must define for eg:
*struct node{
*       xxxx xxxx;your struct member
*   .....
*
*   char   key[128];
*       node * hash_prev;
*   node * hash_next;
*};
*/
enum HASH_TABLE_LEN
{
        HASH_CRC16,
        HASH_CRC32
};
/*hash_link_table template*/
template <class T>
class hash_link_table
{
public:
        hash_link_table(void)
        {
                table = NULL;
                count = 0;
                table_length = 0;
        }

        ~hash_link_table(void)
        {

        }
public:
        bool init_table(HASH_TABLE_LEN len = HASH_CRC16)
        {
                haslen = len;
                if(len == HASH_CRC16)
                {
                        table_length = 0xffff;
                }
                else if(len == HASH_CRC32)
                {
                        table_length = 0xffffffff;
                }

                table =  new pT[table_length + 1];
                if(table == NULL)
                        return false;
                memset(table,0,sizeof(pT) * (table_length + 1));
                return true;
        }

        int size(void)
        {
                return count;
        }

        /*
        *return key:index
        */
        long add(T * pNode,const char * key)
        {
                if(pNode == NULL || key == NULL)
                        return -1;

                if(NULL != find(key))
                        return -2;

                /*get key index*/
                unsigned int key_index = 0;
                if(haslen == HASH_CRC16)
                {
                        key_index = utils::crc16_has_key((ubyte *)key,strlen(key));
                }
                else if(haslen == HASH_CRC32)
                {
                        key_index = utils::crc32_has_key((ubyte *)key,strlen(key));
                }

                T * cnode = table[key_index];

                if(cnode != _NULL)
                {
                        pNode->hash_next = cnode->hash_next;
                        cnode->hash_next = pNode;
                        pNode->hash_prev = cnode;
                        if(pNode->hash_next != _NULL)
                                pNode->hash_next->hash_prev = pNode;
                }
                else
                {
                        table[key_index] = pNode;
                        pNode->hash_next = pNode->hash_prev =_NULL;
                }


                return key_index;
        }

        /*
        *return remove node
        */
        T  * remove(const char * key)
        {
                if(key == _NULL || strlen(key) == 0)
                        return _NULL;

                T  * retNode = NULL;
                uint32_t key_index = 0;
                /*get key index*/
                if(haslen == HASH_CRC16)
                {
                        key_index = utils::crc16_has_key((ubyte *)key,strlen(key));
                }
                else if(haslen == HASH_CRC32)
                {
                        key_index = utils::crc32_has_key((ubyte *)key,strlen(key));
                }

                /*find  node by key and index*/
                T  * cnode = table[key_index];
                while(cnode != _NULL)
                {
                        if(strcmp(key,cnode->key) == 0)
                                break;
                        cnode = cnode->hash_next;
                }
                if(cnode != _NULL)
                {
                        retNode = cnode;
                        if(cnode->hash_prev == _NULL)
                        {
                                table[key_index] = cnode->hash_next;
                                if(cnode->hash_next != _NULL)
                                {
                                        cnode->hash_next->hash_prev = _NULL;
                                }
                        }
                        else
                        {
                                cnode->hash_prev->hash_next = cnode->hash_next;
                                if(cnode->hash_next != _NULL)
                                {
                                        cnode->hash_next->hash_prev = cnode->hash_prev;
                                }
                        }

                }

                return retNode;
        }
        /*
        *return find node
        */
        T  * find(const char * key)
        {
                if(key == _NULL || strlen(key) == 0)
                        return _NULL;

                uint32_t key_index = 0;
                /*get key index*/
                if(haslen == HASH_CRC16)
                {
                        key_index = utils::crc16_has_key((ubyte *)key,strlen(key));
                }
                else if(haslen == HASH_CRC32)
                {
                        key_index = utils::crc32_has_key((ubyte *)key,strlen(key));
                }

                if(_NULL == table[key_index])
                        return _NULL;
                else
                {
                        T * cnode = table[key_index];
                        while(cnode != _NULL)
                        {
                                if(strcmp(key,cnode->key) == 0)
                                        break;
                                cnode = cnode->hash_next;
                        }
                        /*check key list*/
                        return  cnode;
                }
        }
protected:
        typedef T*  pT;
private:
        T ** table;
        HASH_TABLE_LEN haslen;
        unsigned int count;
        size_t table_length;
};

#endif /* HASH_LINK_TABLE_H_ */
